/** @format */

import { findPass } from '../utils/findPass'
import { formatQuery } from '../utils/formatJdQuery'

export class JdBaseDao {
  private db: any
  context: any
  constructor(context: any, private dbName: string) {
    this.context = context
    this.db = context.cloud.db
    this.dbName = dbName
  }
  /**
   * 查询一条数据
   * @param query
   * @param projection
   */
  async findOne(query: Record<string, any>, projection: Record<string, any> = {}, force = false) {
    const pass = findPass(query, projection, force)
    if (!pass) {
      throw Error('参数存在undefined，不允许继续执行')
    }
    const time1 = new Date().getTime()
    query = formatQuery(query)
    const time2 = new Date().getTime()
    const result = await this.db
      .collection(this.dbName)
      .find(query, {
        ...projection,
        limit: 1
      })
      .toArray()
    const time3 = new Date().getTime()
    console.log('findOne', time3 - time2, this.dbName)
    const res = result[0]
    if (res?._id) {
      res._id = res._id.toString()
    }
    return res
  }
  /**
   * 查询多条数据
   * @param query
   * @param projection
   */
  async find(query: Record<string, any>, projection: Record<string, any> = {}, force = false) {
    const pass = findPass(query, projection, force)
    if (!pass) {
      throw Error('参数存在undefined，不允许继续执行')
    }
    const time1 = new Date().getTime()
    query = formatQuery(query)
    const time2 = new Date().getTime()
    const result = await this.db
      .collection(this.dbName)
      .find(query, {
        ...projection
      })
      .toArray()
    const time3 = new Date().getTime()
    console.log('find', time3 - time2, this.dbName)
    return result?.map((v: any) => {
      if (v._id) {
        v._id = v._id.toString()
      }
      return v
    })
  }

  /**
   * 插入单条数据
   * @param document
   */
  async insertOne(document: Record<string, any>) {
    const time1 = new Date().getTime()
    const res = await this.db.collection(this.dbName).insertOne(document)
    const time2 = new Date().getTime()
    console.log('insertOne 2-1', time2 - time1, this.dbName)
    return res?.insertedId?.toString() || ''
  }

  /**
   * 插入多条数据
   * @param documents 插入对象
   *
   * { acknowledged: true, insertedCount: 2, insertedIds: [ new ObjectId("61a5cc1570de855b4ddd6d01"), new ObjectId("61a5cc1570de855b4ddd6d02")] }
   */
  async insertMany(documents: Record<string, any>[]) {
    const time1 = new Date().getTime()
    const res = await this.db.collection(this.dbName).insertMany(documents)
    const time2 = new Date().getTime()
    console.log('insertMany', time2 - time1, this.dbName)
    return Object.values(res?.insertedIds || {}).map((v: any) => v.toString())
  }

  /**
   * 更新数据
   * @param query
   * @param options
   */
  async update(query: Record<string, any>, options?: Record<string, any>) {
    const time1 = new Date().getTime()
    query = formatQuery(query)

    const time2 = new Date().getTime()
    const res = await this.db.collection(this.dbName).updateMany(query, options)

    const time3 = new Date().getTime()
    console.log('update', time3 - time2, this.dbName)
    return res?.modifiedCount || 0
  }

  /**
   * 删除多条数据
   * @param filter
   */
  async delete(filter: Record<string, any>) {
    const time1 = new Date().getTime()
    filter = formatQuery(filter)
    const time2 = new Date().getTime()
    const res = await this.db.collection(this.dbName).deleteMany(filter)
    const time3 = new Date().getTime()
    console.log('delete', time3 - time2, this.dbName)
    return res?.deletedCount || 0
  }

  /**
   * 获取条目数
   * @param query
   * @param options
   */
  async count(query: Record<string, any>, options?: Record<string, any>) {
    const time1 = new Date().getTime()
    query = formatQuery(query)
    const time2 = new Date().getTime()
    const res = await this.db.collection(this.dbName).count(query, options)

    const time3 = new Date().getTime()
    console.log('count', time3 - time2, this.dbName)
    return res
  }

  /**
   * 聚合查询
   * @param query
   * @param options
   */
  async aggregate(aggregateOperation: Record<string, any> | any[]) {
    // console.log(aggregateOperation, 'aggregateOperation1')
    const time1 = new Date().getTime()
    aggregateOperation.forEach((operation: { $match: Record<string, any> }) => {
      if (operation?.$match) {
        operation.$match = formatQuery(operation.$match)
        // console.log(operation, operation.$match, 'option')
      }
    })
    const time2 = new Date().getTime()
    // console.log(aggregateOperation, 'aggregateOperation1')
    const res = await this.db.collection(this.dbName).aggregate(aggregateOperation).toArray()
    const time3 = new Date().getTime()
    console.log('aggregate', time3 - time2, this.dbName)
    return res
  }
}
